﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Testicide.Models;
using Testicide.DAL;
using WatiN.Core;
using System.Threading;
using WatiN.Core.Exceptions;

namespace Testicide.Controllers
{
    public class ScenarioController : Controller
    {

        private TesticideContext db = new TesticideContext();
        private Dictionary<int, string> _result;
        public ScenarioController()
        {
            _result = new Dictionary<int, string>();
            _result.Add(1, "Test Done");
            _result.Add(2, "Message doesn't exist");
            _result.Add(3, "The hostname you are trying to access couldn't be found");
            _result.Add(4, "The required page doesn't appear when clicking on the link");
            _result.Add(5, "The link couldn't be found");
            _result.Add(6, "The Text field couldn't be found");
            _result.Add(7, "The Button couldn't be found");
            _result.Add(8, "The Text field is disabled");
        }
        //
        // GET: /Scenario/

        public ActionResult Index()
        {
            Scenario sc = TempData["fID"] as Scenario;
            if(sc != null)
            {
                var scenario = from s in db.Scenario where s.FeatureID == sc.FeatureID select s;
                return View(scenario.ToList());
            }
            else
            {
                return View(db.Scenario.ToList());
            }
            
        }

        //
        // GET: /Scenario/Details/5

        public ActionResult Details(int id = 0)
        {
            Scenario scenario = db.Scenario.Find(id);
            if (scenario == null)
            {
                return HttpNotFound();
            }
            TempData["fID"] = scenario;
            return View(scenario);
        }

        //
        // GET: /Scenario/Create

        public ActionResult Create()
        {
            //ViewBag.FeatureID = new System.Web.Mvc.SelectList(db.Feature, "ID", "Name");
            //TempData["FeatureID"] = ViewBag.FeatureID;
            return View();
        }

        //
        // POST: /Scenario/Create

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Scenario scenario)
        {
            scenario.Date = DateTime.Now;
            scenario.FeatureID = (int)TempData["FeatureID"];
            if (ModelState.IsValid)
            {
                db.Scenario.Add(scenario);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            ViewBag.FeatureID = new System.Web.Mvc.SelectList(db.Feature, "ID", "Name", scenario.FeatureID);
            return View(scenario);
        }

        //
        // GET: /Scenario/Edit/5

        public ActionResult Edit(int id = 0)
        {
            Scenario scenario = db.Scenario.Find(id);
            if (scenario == null)
            {
                return HttpNotFound();
            }
            TempData["fID"] = scenario;
            ViewBag.FeatureID = new System.Web.Mvc.SelectList(db.Feature, "ID", "Name", scenario.FeatureID);
            return View(scenario);
        }

        //
        // POST: /Scenario/Edit/5

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(Scenario scenario)
        {
            if (ModelState.IsValid)
            {
                db.Entry(scenario).State = EntityState.Modified;
                db.SaveChanges();
                TempData["fID"] = scenario;
                return RedirectToAction("Index");
            }
            ViewBag.FeatureID = new System.Web.Mvc.SelectList(db.Feature, "ID", "Name", scenario.FeatureID);
            return View(scenario);
        }

        //
        // GET: /Scenario/Delete/5

        public ActionResult Delete(int id = 0)
        {
            Scenario scenario = db.Scenario.Find(id);
            if (scenario == null)
            {
                return HttpNotFound();
            }
            TempData["fID"] = scenario;
            return View(scenario);
        }

        //
        // POST: /Scenario/Delete/5

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Scenario scenario = db.Scenario.Find(id);
            db.Scenario.Remove(scenario);
            db.SaveChanges();
            TempData["fID"] = scenario;
            return RedirectToAction("Index");
        }
        
        public ActionResult DeleteRecord(int id)
        {
            Scenario scenario = db.Scenario.Find(id);
            db.Scenario.Remove(scenario);
            db.SaveChanges();
            TempData["featureID"] = scenario.FeatureID;
            return RedirectToAction("Tool_Box");
        }

        public ActionResult Tool_Box(int? id)
        {
            ViewBag.toolboxItems = db.ScenarioToolBox.ToList();
            int FeatureId = 0;
            if(id != null)
            {
                Feature f = db.Feature.Find(id);//(Feature) TempData["mID"];
                FeatureId = f.ID;
                TempData["featureID"] = FeatureId;
                ViewBag.featureText = f.Name;
                ViewBag.FeatureID = f.ID;
            }
            else
            {
                FeatureId = (int)TempData["featureID"];
                TempData["featureID"] = FeatureId;
                ViewBag.featureText = db.Feature.Find(FeatureId).Name;
            }
            var scenariolist = from s in db.Scenario where s.FeatureID == FeatureId select s;
            return View(scenariolist.ToList());
        }
        //
        //This method is used to know which item from the toolbox the user has chosen
        //Then save that choice in the database
        //
        public void HandleSelection(int id)
        {
            int f = (int)TempData["featureID"];
            TempData["featureID"] = f;
            Scenario scenario = new Scenario();
            scenario.Content = db.ScenarioToolBox.Find(id).Content;
            scenario.Title = db.ScenarioToolBox.Find(id).Title;
            scenario.ToolboxItem = id;
            scenario.Date = DateTime.Now;
            scenario.FeatureID = f;
            db.Scenario.Add(scenario);
            db.SaveChanges();
            var scenariolist = from s in db.Scenario where s.FeatureID == f select s;
            ViewBag.toolboxItems = db.ScenarioToolBox.ToList();
        }
        //
        //Run all scenarios in a specific feature
        //
        private int runAllFlag;
        public void RunAll()
        {
            runAllFlag = 1;
            int featureID = (int)TempData["featureID"];
            var scenarios = from s in db.Scenario where s.FeatureID == featureID select s;
            foreach(var item in scenarios)
            {
                getText(item.ID, item.Content, item.Title);
            }
            db.SaveChanges();
            runAllFlag = 0;
            TempData["featureID"] = featureID;
        }
        //
        //This method is used to get the text from the text box after being modified by the user and split that text to 
        //know the page name and the message that the user has added
        //This method is invoked when the user clicks the "Run Test" button
        //
        public void getText(int scenarioId, string text, string title)
        {
            string page_name;
            string messageORpage;
            string linkORbuttonID;
            string textfieldContent;
            string textfieldID;
            string textfieldContent2;
            string textfieldID2;
            string textfieldContent3;
            string textfieldID3;
            string textfieldContent4;
            string textfieldID4;
            int result = 0;
            
            Scenario scenario = db.Scenario.Find(scenarioId);
            scenario.Content = text;
            scenario.Title = title;

            if (scenario.ToolboxItem == 2 || scenario.ToolboxItem == 9)//Browsing to a page English, Arabic
            {
                string[] scenarioArray = text.Split(new string[] { "'" }, StringSplitOptions.None);
                page_name = scenarioArray[1];
                messageORpage = scenarioArray[3];
                result = test(page_name, messageORpage, "", "", "", "","","","","","", (int)scenario.ToolboxItem);
            }

                else if(scenario.ToolboxItem == 3)//Login
            {
                string[] scenarioArray = text.Split(new string[] { "'" }, StringSplitOptions.None);
                page_name = scenarioArray[1];
                textfieldContent = scenarioArray[3];
                textfieldID = scenarioArray[5];
                textfieldContent2 = scenarioArray[7];
                textfieldID2 = scenarioArray[9];
                linkORbuttonID = scenarioArray[11];
                messageORpage = scenarioArray[13];
                result = test(page_name, messageORpage, linkORbuttonID, textfieldContent, textfieldID, textfieldContent2, textfieldID2, "", "", "", "", (int)scenario.ToolboxItem);
            }

                else if(scenario.ToolboxItem == 4)//Create Account
            {
                string[] scenarioArray = text.Split(new string[] { "'" }, StringSplitOptions.None);
                page_name = scenarioArray[1];
                textfieldContent = scenarioArray[3];//username
                textfieldID = scenarioArray[5];
                textfieldContent2 = scenarioArray[7];//password
                textfieldID2 = scenarioArray[9];
                textfieldContent3 = scenarioArray[11];//confirm password
                textfieldID3 = scenarioArray[13];
                textfieldContent4 = scenarioArray[15];//email
                textfieldID4 = scenarioArray[17];
                linkORbuttonID = scenarioArray[19];
                messageORpage = scenarioArray[21];
                result = test(page_name, messageORpage, linkORbuttonID, textfieldContent, textfieldID, textfieldContent2, textfieldID2, textfieldContent3, textfieldID3, textfieldContent4, textfieldID4, (int)scenario.ToolboxItem);
            }

                else if(scenario.ToolboxItem == 5 || scenario.ToolboxItem == 6)//Click a link or Press a button
            {
                string[] scenarioArray = text.Split(new string[] { "'" }, StringSplitOptions.None);
                page_name = scenarioArray[1];
                linkORbuttonID = scenarioArray[3];//or the button id in case toolbox item = 6
                messageORpage = scenarioArray[5];
                result = test(page_name, messageORpage, linkORbuttonID, "", "", "", "", "", "", "", "", (int)scenario.ToolboxItem);
            }

                else if (scenario.ToolboxItem == 7 || scenario.ToolboxItem == 8)//fill a textfield then click a link or press a button
            {
                string[] scenarioArray = text.Split(new string[] { "'" }, StringSplitOptions.None);
                page_name = scenarioArray[1];
                textfieldContent = scenarioArray[3];
                textfieldID = scenarioArray[5];
                linkORbuttonID = scenarioArray[7];
                messageORpage = scenarioArray[9];
                result = test(page_name, messageORpage, linkORbuttonID, textfieldContent, textfieldID, "", "", "", "", "", "", (int)scenario.ToolboxItem);
            }
            //checking the results of the test 
            if (result == 1)
            {
                scenario.Status = Scenario_Status.Pass;
                scenario.Error_message = "";
            }
            else
            {
                scenario.Status = Scenario_Status.Fail;
                scenario.Error_message = _result[result];
            }
            if(runAllFlag != 1)
            { 
                db.SaveChanges();
            }
            
        }
        //
        //This method is used to create new thread in which the test function that will open the browser will be executed
        //because it can't be executed in the same thread (it throws an exception)
        //This function calls the function (test2) that will perform the actual testing
        //
        private IE _browser;
        public int test(string page_name, string messageORpage, string linkID, string textfieldContent, string textfieldID, string textfieldContent2, string textfieldID2, string textfieldContent3, string textfieldID3, string textfieldContent4, string textfieldID4, int selectionID)
        {
            int res = 0;
            Thread mythread = new Thread(() => res = test2(page_name, messageORpage, linkID, textfieldContent, textfieldID, textfieldContent2, textfieldID2, textfieldContent3, textfieldID3, textfieldContent4, textfieldID4, selectionID));
            mythread.SetApartmentState(ApartmentState.STA);
            mythread.Start();
            mythread.Join();
            return res;
        }
        //
        //This is the function that performs the actual testing
        //
        public int test2(string page_name, string messageORpage, string linkID, string textfieldContent, string textfieldID, string textfieldContent2, string textfieldID2, string textfieldContent3, string textfieldID3, string textfieldContent4, string textfieldID4, int selectionID)
        {
            int result = 0;
            try 
            {
                _browser = new IE();
                _browser.GoTo(page_name);
                if (selectionID == 2 || selectionID == 9) //Browsing to a page
                { 
                    bool exist = _browser.ContainsText(messageORpage);
                    if (exist)
                    {
                        result = 1;//test done
                    }
                    else
                    {
                        result = 2;//Message doesn't exist
                    }
                
                }
                
                else if(selectionID==3) //login
                {
                        var textfield = _browser.TextField(textfieldID);
                        var textfield2 = _browser.TextField(textfieldID2);
                    try
                    {
                        textfield.TypeText(textfieldContent);
                        textfield2.TypeText(textfieldContent2);
                        var button = _browser.Button(linkID);
                            try
                            {
                                button.Click();
                                bool exist = _browser.Title.Equals(messageORpage);
                                if (exist)
                                {
                                    result = 1;//test done
                                }
                                else
                                {
                                    result = 4;//The required page doesn't appear when clicking on the link
                                }
                            }
                            catch (ElementNotFoundException)
                            {
                                result = 7;//button couldn't be found
                            }
                    }
                    catch(ElementNotFoundException)
                    {
                        result = 6;//text field couldn't be found
                    }
                    catch(ElementDisabledException)
                    {
                        result = 8;//Text field is disabled
                    }
                }

                else if (selectionID == 4) //Create Account
                {
                    var textfield = _browser.TextField(textfieldID);
                    var textfield2 = _browser.TextField(textfieldID2);
                    var textfield3 = _browser.TextField(textfieldID3);
                    var textfield4 = _browser.TextField(textfieldID4);
                    try
                    {
                        textfield.TypeText(textfieldContent);
                        textfield2.TypeText(textfieldContent2);
                        textfield3.TypeText(textfieldContent3);
                        textfield4.TypeText(textfieldContent4);
                        var button = _browser.Button(linkID);
                        try
                        {
                            button.Click();
                            bool exist = _browser.Title.Equals(messageORpage);
                            if (exist)
                            {
                                result = 1;//test done
                            }
                            else
                            {
                                result = 4;//The required page doesn't appear when clicking on the link
                            }
                        }
                        catch (ElementNotFoundException)
                        {
                            result = 7;//button couldn't be found
                        }
                    }
                    catch (ElementNotFoundException)
                    {
                        result = 6;//text field couldn't be found
                    }
                    catch (ElementDisabledException)
                    {
                        result = 8;//Text field is disabled
                    }
                }
                
                else if (selectionID == 5 || selectionID == 6) //clicking on a link or a button
                {
                    if(selectionID == 5)
                    { 
                        var link = _browser.Link(linkID);
                        try 
                        {
                            link.Click();
                            bool exist = _browser.Title.Equals(messageORpage);
                            if (exist)
                            {
                                result = 1;//test done
                            }
                            else
                            {
                                result = 4;//The required page doesn't appear when clicking on the link
                            }
                        }
                        catch(ElementNotFoundException) 
                        {
                            result = 5;//link couldn't be found
                        }
                    }
                    else
                    {
                        var button = _browser.Button(linkID);
                        try
                        {
                            button.Click();
                            bool exist = _browser.Title.Equals(messageORpage);
                            if (exist)
                            {
                                result = 1;//test done
                            }
                            else
                            {
                                result = 4;//The required page doesn't appear when clicking on the link
                            }
                        }
                        catch (ElementNotFoundException)
                        {
                            result = 7;//button couldn't be found
                        }
                    }
                }
                else if(selectionID == 7 || selectionID == 8)//filling a text field then clicking on a link(selectionID=7) or a button(selectionID=8) to go to another page
                {
                    var textfield = _browser.TextField(textfieldID);
                    try
                    {
                        textfield.TypeText(textfieldContent);
                        if (selectionID == 7)
                        {
                            var link = _browser.Link(linkID);
                            try
                            {
                                link.Click();
                                bool exist = _browser.Title.Equals(messageORpage);
                                if (exist)
                                {
                                    result = 1;//test done
                                }
                                else
                                {
                                    result = 4;//The required page doesn't appear when clicking on the link
                                }
                            }
                            catch (ElementNotFoundException)
                            {
                                result = 5;//link couldn't be found
                            }
                        }
                        else
                        {
                            var button = _browser.Button(linkID);
                            try
                            {
                                button.Click();
                                bool exist = _browser.Title.Equals(messageORpage);
                                if (exist)
                                {
                                    result = 1;//test done
                                }
                                else
                                {
                                    result = 4;//The required page doesn't appear when clicking on the link
                                }
                            }
                            catch (ElementNotFoundException)
                            {
                                result = 7;//button couldn't be found
                            }
                        }
                    }
                    catch(ElementNotFoundException)
                    {
                        result = 6;//text field couldn't be found
                    }
                    catch(ElementDisabledException)
                    {
                        result = 8;//Text field is disabled
                    }
                }
            }
            catch (UriFormatException)
            {
                result = 3;//The hostname you are trying to access couldn't be found
            }
                        
            _browser.Dispose();
            return result;
        }
        //
        //AutoComplete
        //
        public JsonResult AutoComplete(string term)
        {
            string[] Term = term.Split(new string[] { "'" }, StringSplitOptions.None);
            term = Term[1];
            var result = db.Project.Where(p => p.Url.ToLower().Contains(term.ToLower()))
                .Select(p => p.Url).ToList();

            return this.Json(result, JsonRequestBehavior.AllowGet);
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}